////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_QUATERNION_H__
#define __WN_QUATERNION_H__

#include "WNCore/inc/WNBase.h"

namespace WNMath {
    class WNMatrix33;
    class WNMatrix44;
    class WNVector3;

    class WNQuaternion {
    public:
        WNQuaternion();
        explicit WNQuaternion(const WN_FLOAT32* _f);
        explicit WNQuaternion(WN_FLOAT32 x, WN_FLOAT32 y, WN_FLOAT32 z, WN_FLOAT32 w);

        operator WN_FLOAT32* ();
        operator const WN_FLOAT32* () const;

        WNQuaternion& operator += (const WNQuaternion& _quaternion);
        WNQuaternion& operator -= (const WNQuaternion& _quaternion);
        WNQuaternion& operator *= (const WNQuaternion& _quaternion);
        WNQuaternion& operator *= (WN_FLOAT32 _f);
        WNQuaternion& operator /= (WN_FLOAT32 _f);

        WNQuaternion operator + () const;
        WNQuaternion operator - () const;

        WNQuaternion operator + (const WNQuaternion& _quaternion) const;
        WNQuaternion operator - (const WNQuaternion& _quaternion) const;
        WNQuaternion operator * (const WNQuaternion& _quaternion) const;
        WNQuaternion operator * (WN_FLOAT32 _f) const;
        WNQuaternion operator / (WN_FLOAT32 _f) const;

        friend WNQuaternion operator * (WN_FLOAT32 _f, const WNQuaternion& _quaternion);
        friend WNQuaternion operator / (WN_FLOAT32 _f, const WNQuaternion& _quaternion);

        WN_BOOL operator == (const WNQuaternion& _quaternion) const;
        WN_BOOL operator != (const WNQuaternion& _quaternion) const;

        WN_VOID Zero();
        WN_VOID Identity();
        WN_VOID Normalize();
        WN_VOID Invert();
        WN_VOID Logarithm();
        WN_VOID Exponent();
        WN_VOID Rotate(const WNQuaternion& _rotation);

        WN_FLOAT32 Length() const;
        WN_FLOAT32 LengthSquared() const;

        WN_BOOL IsZero() const;
        WN_BOOL IsIdentity() const;

        WN_VOID Set(const WN_FLOAT32* _f);
        WN_VOID Set(WN_FLOAT32 _x, WN_FLOAT32 _y, WN_FLOAT32 _z, WN_FLOAT32 _w);

        WNQuaternion GetNormalized() const;
        WNQuaternion GetInverted() const;
        WNQuaternion GetConjugate() const;
        WNQuaternion GetLogarithm() const;
        WNQuaternion GetExponent() const;

        WNMatrix44 ToMatrix44() const;

    public:
        union {
            struct {
                WN_FLOAT32 x;
                WN_FLOAT32 y;
                WN_FLOAT32 z;
                WN_FLOAT32 w;
            };

            WN_FLOAT32 raw[4];
        };
    };
}

#endif // __WN_QUATERNION_H__